package com.ctshk.rpc.order.hotel.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ctshk.common.enums.hotel.HotelHasBreakfast;
import com.ctshk.common.enums.order.OrderPaymentRefundType;
import com.ctshk.common.vo.OrderRefundDTO;
import com.ctshk.rpc.finance.req.bill.BillOperateRefundReq;
import com.ctshk.rpc.hotel.dto.HotelProductInfoDTO;
import com.ctshk.rpc.hotel.dto.HotelRoomTypeDTO;
import com.ctshk.rpc.order.hotel.req.HotelCancelOrderReq;
import com.ctshk.rpc.order.hotel.req.HotelOrderPageReq;
import com.ctshk.rpc.order.hotel.req.HotelOrderTouristReq;
import com.ctshk.rpc.order.hotel.service.IHotelOrderCenterService;
import com.ctshk.rpc.system.dto.MainDataPaymentRefundTypeDTO;
import com.ctshk.rpc.system.req.MainDataPaymentRefundTypeIdReq;
import com.google.common.collect.Lists;
import com.ctshk.rpc.finance.json.AccountJson;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.*;
import com.ctshk.common.enums.hotel.HotelOrdersType;
import com.ctshk.common.enums.order.OrderSalesMethods;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.NumberUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.rpc.booking.service.ISupplierOrderService;
import com.ctshk.rpc.finance.req.bill.BillAddRefundReq;
import com.ctshk.rpc.finance.service.IFinanceBillService;
import com.ctshk.rpc.hotel.service.*;
import com.ctshk.rpc.iotc.service.IOperateBankPreferenceService;
import com.ctshk.rpc.order.hotel.dto.*;
import com.ctshk.rpc.order.hotel.dto.HotelOrderCollectionInfoDTO;
import com.ctshk.rpc.order.hotel.dto.HotelOrderDetailDTO;
import com.ctshk.rpc.order.hotel.dto.HotelOrderTouristDTO;
import com.ctshk.rpc.order.hotel.entity.*;
import com.ctshk.rpc.order.hotel.mapper.*;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.req.MainDataCurrencyUpdateStatusReq;
import com.ctshk.rpc.system.service.*;
import com.ctshk.rpc.workflow.dto.ApprovalCheckDTO;
import com.ctshk.rpc.workflow.dto.ApprovalStartDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 酒店订单表 服务实现类
 * </p>
 *
 * @author yinhuan
 * @since 2021-03-08
 */
@Slf4j
@DubboService
public class HotelOrderCenterServiceImpl extends ServiceImpl<HotelOrderMapper, HotelOrder> implements IHotelOrderCenterService {
    @Autowired
    private HotelOrderMapper hotelOrderMapper;
    @Autowired
    private HotelOrderTouristMapper hotelOrderTouristMapper;
    @DubboReference
    private IMainDataCurrencyService iMainDataCurrencyService;
    @Autowired
    private HotelOrderCollectionMapper hotelOrderCollectionMapper;
    @Autowired
    private HotelManualOrderMapper hotelManualOrderMapper;
    @Autowired
    private HotelOrderRefundMapper hotelOrderRefundMapper;
    @Autowired
    private HotelOrderReceiptMapper hotelOrderReceiptMapper;
    @DubboReference
    private IHotelService hotelService;
    @DubboReference
    private IHotelProductService hotelProductService;
    @DubboReference
    private ICrmMemberService crmMemberService;
    @DubboReference
    private IMainDataCurrencyService mainDataCurrencyService;
    @DubboReference
    private ISysUserService sysUserService;
    @DubboReference
    private ISysDepartmentService sysDepartmentService;
    @DubboReference
    private IOperateBankPreferenceService operateBankPreferenceService;
    @DubboReference
    private ISupplierOrderService supplierOrderService;
    @DubboReference
    private ISysPermissionService sysPermissionService;
    @DubboReference
    private IHotelRoomTypeService hotelRoomTypeService;
    @DubboReference
    private ISysApprovalService sysApprovalService;
    @DubboReference
    private IFinanceBillService financeBillService;
    @DubboReference
    private IMainDataPaymentRefundTypeService mainDataPaymentRefundTypeService;


    @Override
    public PageResponse<HotelOrderPageDTO> queyList(HotelOrderPageReq req, long userId) {
        if (req.getMenuId() == null) {
            throw new BusinessException(SystemError.SYSTEM_2106);
        }
        Result<List<Long>> permissionResult = sysPermissionService.queryPermission(req.getMenuId(), userId);
        if (!permissionResult.isSuccess()) {
            SystemError result = SystemError.getDefined(permissionResult.getCode());
            throw new BusinessException(result);
        }

        IPage<HotelOrder> agentPage = new Page<>(req.getPageNo(),req.getPageSize());
        agentPage = hotelOrderMapper.queryList(req, agentPage, permissionResult.getData());
        if(CollectionUtils.isEmpty(agentPage.getRecords())){
            return PageResponse.empty(1);
        }

        List<HotelOrderPageDTO> orderPageDTOS = new ArrayList<>();
        Optional.ofNullable(agentPage.getRecords()).orElse(new ArrayList<>()).forEach(hotelOrder -> {
            HotelOrderPageDTO orderPageDTO = EntityUtil.copy(hotelOrder, HotelOrderPageDTO.class);
            // 产品类型转换
            if (hotelOrder.getIsManual() == 1) {
                orderPageDTO.setProductType("外挂單");
            } else {
                HotelProductInfoDTO hotelProductInfoDTO = hotelProductService.selectById(hotelOrder.getHotelProductId());
                if (null != hotelProductInfoDTO) {
                    if (null == hotelProductInfoDTO.getProductType()) {
                        orderPageDTO.setProductType("未知");
                    } else {
                        orderPageDTO.setProductType(hotelProductInfoDTO.getProductType() == 1 ? "人工錄入" : "API錄入");
                    }
                }
            }
            // 产品间夜转换
            Integer number = hotelOrder.getNumber() == null ? 0 : hotelOrder.getNumber();
            Integer nights = hotelOrder.getNights() == null ? 0 : hotelOrder.getNights();
            orderPageDTO.setRoomNight(number + "間*" + nights + "晚");
            // 产品是否含早转换
            orderPageDTO.setHasBreakFast(HotelHasBreakfast.parseValue(hotelOrder.getHasBreakfast()));
            // 产品来源转换
            orderPageDTO.setSource(OrderSource.getOrderSourceName(hotelOrder.getSource()));
            UserDTO user = sysUserService.queryCacheUser(hotelOrder.getSalesmanId() == null ? hotelOrder.getCreateId() : hotelOrder.getSalesmanId());
            String sales = user.getFullName() + "/" + user.getDept();
            // 销售转换
            orderPageDTO.setSalesmanName(sales);
            orderPageDTOS.add(orderPageDTO);
        });

        PageResponse<HotelOrderPageDTO> result = new PageResponse<>(orderPageDTOS,agentPage.getCurrent() == 1,
                agentPage.getTotal() <= (agentPage.getCurrent() * agentPage.getSize()),
                agentPage.getTotal(), agentPage.getCurrent(), agentPage.getSize());
        return result;
    }

    @Override
    public HotelOrderDetailDTO queryDetail(long id) {
        HotelOrder hotelOrder = hotelOrderMapper.selectById(id);
        if(Objects.isNull(hotelOrder) || hotelOrder.getIsDeleted() == 1){
            throw new BusinessException(SystemError.HOTEL_10031);
        }
        HotelOrderDetailDTO result = EntityUtil.copy(hotelOrder, HotelOrderDetailDTO.class);
        // 产品类型转换
        if (hotelOrder.getIsManual() == 1) {
            result.setProductType("外挂單");
        } else {
            HotelProductInfoDTO hotelProductInfoDTO = hotelProductService.selectInfo(hotelOrder.getHotelProductId());
            if (null != hotelProductInfoDTO) {
                if (null == hotelProductInfoDTO.getProductType()) {
                    result.setProductType("未知");
                } else {
                    result.setProductType(hotelProductInfoDTO.getSourceType() == ProductType.MANUAL_ENTRY.getCode() ? ProductType.MANUAL_ENTRY.getName() : ProductType.API_PRODUCT.getName());
                }
            }
        }
        // 订单销售方式转换
        result.setSalesMethods(hotelOrder.getSalesMethods() == null ? "" : OrderSalesMethods.parseValue(hotelOrder.getSalesMethods()));
        // 产品来源转换
        result.setSource(OrderSource.getOrderSourceName(hotelOrder.getSource()));
        UserDTO user = sysUserService.queryCacheUser(hotelOrder.getSalesmanId() == null ? hotelOrder.getCreateId() : hotelOrder.getSalesmanId());
        String sales = user.getFullName() + "/" + user.getDept();
        // 产品销售转换
        result.setSalesmanName(sales);
        result.setBusinessType("酒店");
        // 获取客户类型
        result.setClientType(HotelOrdersType.parseValue(hotelOrder.getOrdersType()) + " " + hotelOrder.getAgencyCompany());
        // 联系电话转换
        result.setContactMobile(hotelOrder.getContactMobileAreaCode() + "-" + hotelOrder.getContactMobile());
        // 构建订单状态
        buildOrderStatus(result);
        /**
         * 酒店信息
         */
        Integer number = hotelOrder.getNumber() == null ? 0 : hotelOrder.getNumber();
        Integer nights = hotelOrder.getNights() == null ? 0 : hotelOrder.getNights();
        // 判断是否为外挂单,进行相应操作
        if (hotelOrder.getIsManual() != 1) {
            Result<HotelRoomTypeDTO> roomType = hotelRoomTypeService.query(hotelOrder.getRoomId());
            if (!roomType.isSuccess()) {
                SystemError systemError = SystemError.getDefined(roomType.getCode());
                throw new BusinessException(systemError);
            }
            if (null == roomType.getData()) {
                log.error("【酒店订单】酒店信息为空,订单id[{}]", id);
            } else {
                HotelInfoDTO hotelInfo = EntityUtil.copy(roomType.getData(), HotelInfoDTO.class);
                // 产品间夜转换
                hotelInfo.setRoomNight(number + "間*" + nights + "晚");
                // 产品是否含早转换
                hotelInfo.setHasBreakFast(HotelHasBreakfast.parseValue(hotelOrder.getHasBreakfast()));
                hotelInfo.setName(hotelOrder.getHotelName());
                hotelInfo.setRoomName(hotelOrder.getRoomName());
                hotelInfo.setHotelProductName(hotelOrder.getHotelProductName());
                hotelInfo.setBedType(roomType.getData().getBedType());
                hotelInfo.setCheckInDate(hotelOrder.getCheckInDate());
                hotelInfo.setCheckOutDate(hotelOrder.getCheckOutDate());
                result.setHotelInfo(hotelInfo);
            }

            /**
             * 旅客信息
             */
            HotelProductInfoDTO hotelProductDTO = hotelProductService.selectInfo(hotelOrder.getHotelProductId());
            if (hotelProductDTO == null) {
                throw new BusinessException(SystemError.HOTEL_10014);
            }
            List<HotelOrderTourist> hotelOrderTourists = hotelOrderTouristMapper.selectList(Wrappers.<HotelOrderTourist>lambdaQuery()
                    .eq(HotelOrderTourist::getOrderId, id)
                    .eq(HotelOrderTourist::getIsDeleted, 0));
            if (CollUtil.isEmpty(hotelOrderTourists)) {
                log.error("【酒店订单】旅客信息为空,订单id[{}]", id);
            } else {
                HotelOrderTouristInfoDTO orderTourists = new HotelOrderTouristInfoDTO();
                String taxes = "";
                if (null == hotelProductDTO.getTaxation() || hotelProductDTO.getTaxation().compareTo(BigDecimal.ZERO) == 0) {
                    taxes = "无";
                } else {
                    // 税费用=税费*旅客人数
                    taxes = hotelProductDTO.getTaxation() + "*" + hotelOrderTourists.size();
                }
                orderTourists.setTaxes(taxes);
                orderTourists.setTourists(EntityUtil.copyList(hotelOrderTourists, HotelOrderTouristDTO.class));
                Optional.ofNullable(orderTourists.getTourists()).orElse(new ArrayList<>()).forEach(hotelOrderTouristDTO -> {
                    String roomPrice = hotelOrder.getUnitPrice() + "*" + (hotelOrder.getNights() == null ? 1 : hotelOrder.getNights());
                    hotelOrderTouristDTO.setRoomPrice(roomPrice);
                });
                result.setOrderTourists(orderTourists);
            }
        } else {
            HotelInfoDTO hotelInfo = new HotelInfoDTO();
            // 产品间夜转换
            hotelInfo.setRoomNight(number + "間*" + nights + "晚");
            // 产品是否含早转换
            hotelInfo.setHasBreakFast(HotelHasBreakfast.parseValue(hotelOrder.getHasBreakfast()));
            hotelInfo.setName(hotelOrder.getHotelName());
            hotelInfo.setRoomName(hotelOrder.getRoomName());
            hotelInfo.setHotelProductName(hotelOrder.getHotelProductName());
            hotelInfo.setBedType("-");
            hotelInfo.setCheckInDate(hotelOrder.getCheckInDate());
            hotelInfo.setCheckOutDate(hotelOrder.getCheckOutDate());
            result.setHotelInfo(hotelInfo);
        }

        /**
         * 收款记录
         */
        List<HotelOrderCollection> hotelOrderCollections = hotelOrderCollectionMapper.selectList(Wrappers.<HotelOrderCollection>lambdaQuery()
                .eq(HotelOrderCollection::getOrderId, id)
                .eq(HotelOrderCollection::getIsDeleted, 0)
        .orderByDesc(HotelOrderCollection::getGmtCreate));
        if (CollUtil.isEmpty(hotelOrderCollections)) {
            log.info("【酒店订单】收款记录为空,订单id[{}]", id);
        } else {
            List<HotelOrderCollectionInfoDTO> orderCollections = new ArrayList<>();
            hotelOrderCollections.forEach(hotelOrderCollection -> {
                HotelOrderCollectionInfoDTO orderCollection = EntityUtil.copy(hotelOrderCollection, HotelOrderCollectionInfoDTO.class);
                // 获取收款明细的销售信息
                UserDTO collectionUser = sysUserService.queryCacheUser(hotelOrderCollection.getSalerId() == null ? hotelOrderCollection.getCreateId() : hotelOrderCollection.getSalerId());
                String collectionSales = collectionUser.getFullName() + "/" + collectionUser.getDept();
                orderCollection.setSalerName(collectionSales);
                orderCollection.setCollectionAmount(hotelOrderCollection.getCollectionAmount().multiply(hotelOrderCollection.getExchangeRate()).setScale(2, BigDecimal.ROUND_HALF_UP));
                orderCollections.add(orderCollection);
            });
            result.setOrderCollections(orderCollections);
        }

        List<HotelOrderRefund> hotelOrderRefunds = hotelOrderRefundMapper.selectList(Wrappers.<HotelOrderRefund>lambdaQuery()
                .eq(HotelOrderRefund::getOrderId, id)
                .eq(HotelOrderRefund::getIsDeleted, 0)
                .orderByDesc(HotelOrderRefund::getGmtCreate));
        if (CollUtil.isEmpty(hotelOrderRefunds)) {
            log.info("【酒店订单】退款记录为空,订单id[{}]", id);
        } else {
            List<HotelOrderRefundInfoDTO> orderRefunds = new ArrayList<>();
            hotelOrderRefunds.forEach(hotelOrderRefund -> {
                HotelOrderRefundInfoDTO orderRefund = EntityUtil.copy(hotelOrderRefund, HotelOrderRefundInfoDTO.class);
                // 获取退款明细的销售信息
                UserDTO collectionUser = sysUserService.queryCacheUser(hotelOrderRefund.getCreateId());
                String collectionSales = collectionUser.getFullName() + "/" + collectionUser.getDept();
                orderRefund.setApplicant(collectionSales);

                orderRefunds.add(orderRefund);
            });
            result.setHotelOrderRefunds(orderRefunds);
        }

        return result;
    }

    @Override
    @GlobalTransactional
    //@Transactional(rollbackFor = Exception.class)
    public Result cancelOrder(HotelCancelOrderReq req, long userId) {
        //根据订单id查询订单信息
        HotelOrder hotelOrder = hotelOrderMapper.selectById(req.getOrderId());
        if(Objects.isNull(hotelOrder) || hotelOrder.getIsDeleted() == 1){
            throw new BusinessException(SystemError.HOTEL_10031);
        }
        // 获取订单当前状态流程
        Integer paymentStatus = hotelOrder.getPaymentStatus();
        Integer scheduledStatus = hotelOrder.getScheduledStatus();
        Integer cancelStatus = hotelOrder.getCancelStatus();

        if (paymentStatus.equals(OrderPaymentStatus.ALREADY_CANCEL.getCode())) {
            throw new BusinessException(SystemError.HOTEL_10085);
        }
        if (ApprovalStatus.REVIEWING.getCode().equals(cancelStatus)
                || ApprovalStatus.REVIEW_YES.getCode().equals(cancelStatus)) {
            throw new BusinessException(SystemError.HOTEL_10086);
        }

        // 代付款状态可直接取消订单
        if (paymentStatus.equals(OrderPaymentStatus.UN_PAYMENT.getCode())) {
            hotelOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_CANCEL.getCode());
            hotelOrder.setCancelReason(req.getCancelReason());
            hotelOrder.setCancelRemark(req.getRemark());
            hotelOrder.setGmtModified(LocalDateTime.now());
            hotelOrder.setModifiedId(userId);
            hotelOrderMapper.updateById(hotelOrder);
            return Result.success(hotelOrder.getId());
        }

        /**
         * 代付款状态取消订单需3步
         * 第一步：发起取消订单审批
         * 第二步：审批通过后执行财务退款
         * 第三步：财务退款完成后执行取消订单
         * 注：第二,三步不在此方法内执行
          */
        if (paymentStatus.equals(OrderPaymentStatus.ALREADY_PAYMENT.getCode())) {
            if (CollUtil.isEmpty(req.getOrderRefundReqs())) {
                throw new BusinessException(SystemError.HOTEL_10084);
            }
            LocalDateTime now = LocalDateTime.now();
            Long orderId = hotelOrder.getId();
            String cancelReason = req.getCancelReason();

            // 修改订单状态
            hotelOrder.setCancelStatus(ApprovalStatus.REVIEWING.getCode());
            hotelOrder.setCancelReason(cancelReason);
            hotelOrder.setCancelRemark(req.getRemark());
            hotelOrder.setGmtModified(now);
            hotelOrder.setModifiedId(userId);
            hotelOrderMapper.updateById(hotelOrder);

            JSONArray refundIdsJson = new JSONArray();
            // 新增退款明细
            List<HotelOrderRefund> hotelOrderRefunds = EntityUtil.copyList(req.getOrderRefundReqs(), HotelOrderRefund.class);
            hotelOrderRefunds.forEach(hotelOrderRefund -> {
                // 获取对应汇率
                MainDataCurrencyQueryDTO currencyQueryDTO = getExchangeRateByName(hotelOrderRefund.getCurrencyId());
                JSONObject refundIdJson = new JSONObject();
                Long refundId = SnowflakeIdWorker.nextId();
                hotelOrderRefund.setId(refundId);
                hotelOrderRefund.setOrderId(orderId);
                hotelOrderRefund.setExchangeRate(currencyQueryDTO.getMarketExchangeRate());
                hotelOrderRefund.setRefundReason(cancelReason);
                hotelOrderRefund.setRemark(req.getRemark());
                hotelOrderRefund.setRefundNumber(NumberUtil.generateOrderHotelRefundNumber(now));
                hotelOrderRefund.setStatus(ApprovalStatus.REVIEWING.getCode());
                hotelOrderRefund.setGmtCreate(now);
                hotelOrderRefund.setGmtModified(now);
                hotelOrderRefund.setCreateId(userId);
                hotelOrderRefund.setIsDeleted(0);

                refundIdJson.put("refundId", refundId);
                refundIdsJson.add(refundIdJson);
            });

            hotelOrderRefundMapper.insertBatchSomeColumn(hotelOrderRefunds);

            // 发起取消审批
            Result<ApprovalStartDTO> approval = sysApprovalService.start(SystemBusinessType.HOTEL.getCode(), SysApprovalType.CANCEL_HOTEL.getCode(), orderId, userId, null, refundIdsJson.toJSONString());
            if (!approval.isSuccess()) {
                SystemError systemError = SystemError.getDefined(approval.getCode());
                throw new BusinessException(systemError);
            }

            return Result.success(hotelOrder.getId());
        }

        return Result.success(hotelOrder.getId());
    }

    @Override
    @GlobalTransactional
    //@Transactional(rollbackFor = Exception.class)
    public Long check(long approvalId, long userId, int status, String comments, String extendParams, BigDecimal actualRefundAmount) {
        Result<ApprovalCheckDTO> checkDTOResult = sysApprovalService.check(approvalId, userId, status, comments);
        if (!checkDTOResult.isSuccess()) {
            SystemError systemError = SystemError.getDefined(checkDTOResult.getCode());
            throw new BusinessException(systemError);
        }

        log.info("整个审批流程是否完成[{}]", checkDTOResult.getData().getIsFinish());

        if (ApprovalStatus.REVIEW_YES.getCode().equals(status) && !checkDTOResult.getData().getIsFinish()) {
            // 审批通过但未完成则不操作业务数据
            return approvalId;
        }

        HotelOrderRefund hotelOrderRefund = new HotelOrderRefund();

        hotelOrderRefund.setStatus(status);
        hotelOrderRefund.setActualRefundAmount(actualRefundAmount);
        hotelOrderRefund.setRejectReason(comments);

        JSONArray idsArray = JSONArray.parseArray(extendParams);
        List<Long> ids = new ArrayList<>();
        idsArray.forEach(o -> {
            JSONObject object = JSONObject.parseObject(o.toString());
            ids.add(object.getLong("refundId"));
        });

        log.info("修改退款明细的审批状态,退款明细ids:[{}]", ids);

        hotelOrderRefundMapper.update(hotelOrderRefund, Wrappers.<HotelOrderRefund>lambdaQuery()
        .in(HotelOrderRefund::getId, ids));

        List<HotelOrderRefund> orderRefunds = hotelOrderRefundMapper.selectList(Wrappers.<HotelOrderRefund>lambdaQuery()
                .in(HotelOrderRefund::getId, ids)
                .eq(HotelOrderRefund::getIsDeleted, 0));
        HotelOrder hotelOrder = hotelOrderMapper.selectById(orderRefunds.get(0).getOrderId());
        HotelProductInfoDTO hotelProductDTO = hotelProductService.selectInfo(hotelOrder.getHotelProductId());
        String orderNumber = hotelOrder.getOrderNumber();
        Long saleUserId = orderRefunds.get(0).getCreateId();
        UserDTO saleUserDTO = sysUserService.queryCacheUser(saleUserId);
        Integer touristSource = 1;
        if (hotelOrder.getOrdersType() == 2) {
            // 财务服务的代理商类型是3
            touristSource = 3;
        } else if (hotelOrder.getOrdersType() == 3) {
            // 财务服务的大客户类型是3
            touristSource = 2;
        }

        finaceRefund(orderRefunds, orderNumber, Arrays.asList(hotelOrder.getHotelProductId()), hotelProductDTO.getName(), hotelProductDTO.getName(), saleUserId, saleUserDTO.getFullName(), saleUserDTO.getDeptId(), hotelOrder.getContactName(), hotelOrder.getContactMobile(), touristSource, hotelOrder.getAgencyId(), hotelOrder.getAgencyCompany());

        return approvalId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long confirmOrder(long id, String confirmNumber, long userId) {
        //根据订单id查询订单信息
        HotelOrder hotelOrder = hotelOrderMapper.selectById(id);
        if(Objects.isNull(hotelOrder) || hotelOrder.getIsDeleted() == 1){
            throw new BusinessException(SystemError.HOTEL_10031);
        }
        hotelOrder.setConfirmNumber(confirmNumber);
        hotelOrder.setGmtModified(LocalDateTime.now());
        hotelOrder.setModifiedId(userId);
        hotelOrderMapper.updateById(hotelOrder);
        return id;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BigDecimal refundAmount(long id) {
        //根据订单id查询订单信息
        HotelOrder hotelOrder = hotelOrderMapper.selectById(id);
        if(Objects.isNull(hotelOrder) || hotelOrder.getIsDeleted() == 1){
            throw new BusinessException(SystemError.HOTEL_10031);
        }

        HotelProductInfoDTO hotelProductInfoDTO = hotelProductService.selectInfo(hotelOrder.getHotelProductId());

        BigDecimal receiptAmount = hotelOrder.getReceiptAmount();
        // 获取退款手续费
        BigDecimal refundCharge = new BigDecimal(0);
        if (hotelProductInfoDTO.getRefundChargeType().equals(ServiceChargeType.PERCENTAGE.getCode())) {
            BigDecimal percentage = hotelProductInfoDTO.getRefundCharge().divide(new BigDecimal("100"));
            refundCharge = hotelOrder.getReceivableAmount().multiply(percentage);
        } else if (hotelProductInfoDTO.getRefundChargeType().equals(ServiceChargeType.FIXED.getCode())) {
            refundCharge = hotelProductInfoDTO.getRefundCharge();
        }
        // 获取银行优惠金额
        HotelOrderCollection hotelOrderCollection = hotelOrderCollectionMapper.selectOne(Wrappers.<HotelOrderCollection>lambdaQuery()
                .eq(HotelOrderCollection::getOrderId, id)
                .eq(HotelOrderCollection::getIsUnionpayDiscount, 1)
                .eq(HotelOrderCollection::getIsDeleted, 0));
        BigDecimal unionpayDiscount = new BigDecimal(0);
        if (hotelOrderCollection != null) {
            unionpayDiscount = hotelOrderCollection.getCollectionAmount();
        }

        // 获取推广码优惠金额
        BigDecimal couponDeduction = hotelOrder.getCouponDeduction() == null ? BigDecimal.ZERO : hotelOrder.getCouponDeduction();

        log.info("订单实收金额receiptAmount[{}], 退款手续费refundCharge[{}], 银行优惠unionpayDiscount[{}], 推广码优惠金额couponDeduction[{}]", receiptAmount, refundCharge, unionpayDiscount, couponDeduction);
        // 最大可退金额=實收金額-手續費-銀行優惠-推廣碼
        BigDecimal refundAmount = receiptAmount.subtract(refundCharge).subtract(unionpayDiscount).subtract(couponDeduction);
        return refundAmount;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result finaceReject(String collectionNumber, long userId, Integer status, String rejectInfo) {
        HotelOrderCollection orderCollection = hotelOrderCollectionMapper.selectOne(Wrappers.<HotelOrderCollection>lambdaQuery()
                .eq(HotelOrderCollection::getCollectionNumber, collectionNumber)
                .eq(HotelOrderCollection::getIsDeleted, 0));
        if (orderCollection == null || orderCollection.getIsDeleted() == 1) {
            throw new BusinessException(SystemError.SYS_411);
        }
        orderCollection.setStatus(status);
        orderCollection.setRejectInfo(rejectInfo);
        orderCollection.setModifiedId(userId);
        orderCollection.setGmtModified(LocalDateTime.now());
        hotelOrderCollectionMapper.updateById(orderCollection);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result supplierConfirmOrder(String orderNumber, Integer status, long userId) {
        //根据订单id查询订单信息
        HotelOrder hotelOrder = hotelOrderMapper.selectOne(Wrappers.<HotelOrder>lambdaQuery()
                .eq(HotelOrder::getOrderNumber, orderNumber)
                .eq(HotelOrder::getIsDeleted, 0));
        if(Objects.isNull(hotelOrder)){
            throw new BusinessException(SystemError.HOTEL_10031);
        }

        hotelOrder.setScheduledStatus(status);
        hotelOrder.setModifiedId(userId);
        hotelOrder.setGmtModified(LocalDateTime.now());
        hotelOrderMapper.updateById(hotelOrder);
        return Result.success(hotelOrder.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long delRefund(long id, long userId) {
        HotelOrderRefund orderRefund = hotelOrderRefundMapper.selectById(id);
        if (orderRefund == null || orderRefund.getIsDeleted() == 1) {
            throw new BusinessException(SystemError.SYS_411);
        }

        orderRefund.setModifiedId(userId);
        orderRefund.setIsDeleted(1);
        orderRefund.setGmtModified(LocalDateTime.now());
        hotelOrderRefundMapper.updateById(orderRefund);

        return orderRefund.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long reconfirm(long id, long userId) {
        HotelOrderCollection orderCollection = hotelOrderCollectionMapper.selectById(id);
        if (orderCollection == null || orderCollection.getIsDeleted() == 1) {
            throw new BusinessException(SystemError.SYS_411);
        }

        BillOperateRefundReq req = new BillOperateRefundReq();
        req.setBillNumber(orderCollection.getCollectionNumber());
        req.setBusinessType(SystemBusinessType.HOTEL.getCode());
        req.setUserId(userId);

        Result result = financeBillService.reConfirm(req);
        if (!result.isSuccess()) {
            SystemError systemError = SystemError.getDefined(result.getCode());
            throw new BusinessException(systemError);
        }
        return id;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long confirmRefund(long id, long userId) {
        HotelOrderRefund orderRefund = hotelOrderRefundMapper.selectById(id);
        if (orderRefund == null || orderRefund.getIsDeleted() == 1) {
            throw new BusinessException(SystemError.SYS_411);
        }
        MainDataPaymentRefundTypeIdReq req = new MainDataPaymentRefundTypeIdReq();
        req.setId(orderRefund.getRefundWayId());
        MainDataPaymentRefundTypeDTO paymentRefundTypeDTO = mainDataPaymentRefundTypeService.query(req);
        log.info("获取到的支付方式主数据code[{}]", paymentRefundTypeDTO.getCode());
        if (!OrderPaymentRefundType.OTP.name().equals(paymentRefundTypeDTO.getCode())) {
            throw new BusinessException(SystemError.HOTEL_ORDER_REFUND_10087);
        }
        if (!ApprovalStatus.REVIEW_YES.getCode().equals(orderRefund.getStatus())) {
            throw new BusinessException(SystemError.HOTEL_ORDER_REFUND_10088);
        }
        orderRefund.setModifiedId(userId);
        //退款成功
        orderRefund.setStatus(5);
        int update = hotelOrderRefundMapper.updateById(orderRefund);
        if (update <= 0){
            throw new BusinessException(SystemError.SYS_408);
        }
        BillOperateRefundReq billOperateRefundReq = new BillOperateRefundReq();
        billOperateRefundReq.setBillNumber(orderRefund.getRefundNumber());
        billOperateRefundReq.setBusinessType(SystemBusinessType.HOTEL.getCode());
        billOperateRefundReq.setUserId(userId);
        Result result = financeBillService.operateRefund(billOperateRefundReq);
        if (!result.isSuccess()) {
            SystemError systemError = SystemError.getDefined(result.getCode());
            throw new BusinessException(systemError);
        }
        return id;
    }

    /**
     * 财务中心-操作退款
     *
     * @param refundNumber
     * @param userId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result financeConfirmRefund(String refundNumber, Long userId) {
        QueryWrapper<HotelOrderRefund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("refund_number",refundNumber);
        queryWrapper.eq("is_deleted",0);
        HotelOrderRefund refund = hotelOrderRefundMapper.selectOne(queryWrapper);
        if (refund == null){
            throw new BusinessException(SystemError.SYS_411);
        }
        MainDataPaymentRefundTypeIdReq req = new MainDataPaymentRefundTypeIdReq();
        req.setId(refund.getRefundWayId());
        MainDataPaymentRefundTypeDTO paymentRefundTypeDTO = mainDataPaymentRefundTypeService.query(req);
        log.info("获取到的支付方式主数据code[{}]", paymentRefundTypeDTO.getCode());
        if (!OrderPaymentRefundType.OTP.name().equals(paymentRefundTypeDTO.getCode())) {
            throw new BusinessException(SystemError.HOTEL_ORDER_REFUND_10087);
        }
        if (!ApprovalStatus.REVIEW_YES.getCode().equals(refund.getStatus())) {
            throw new BusinessException(SystemError.HOTEL_ORDER_REFUND_10088);
        }
        refund.setModifiedId(userId);
        //退款成功
        refund.setStatus(5);
        int update = hotelOrderRefundMapper.updateById(refund);
        if (update <= 0){
            throw new BusinessException(SystemError.SYS_408);
        }
        return Result.success(refund.getId());
    }

    /**
     * 财务中心-退款列表
     *
     * @param orderId
     * @return
     */
    @Override
    public Result<List<OrderRefundDTO>> financeRefundList(Long orderId) {
        List<OrderRefundDTO> dtoList = new ArrayList<>();
        QueryWrapper<HotelOrderRefund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id",orderId);
        queryWrapper.eq("is_deleted",0);
        List<HotelOrderRefund> list = hotelOrderRefundMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(list)){
            return Result.success(dtoList);
        }
        for (HotelOrderRefund refund : list) {
            OrderRefundDTO dto = EntityUtil.copy(refund,OrderRefundDTO.class);
            dto.setBusinessType(SystemBusinessType.HOTEL.getCode());
            dto.setApprovalAmount(refund.getActualRefundAmount());
            dto.setRefundType(refund.getRefundWay());
            dtoList.add(dto);
        }
        return Result.success(dtoList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long modifyTourist(List<HotelOrderTouristReq> reqs, long id, long userId) {
        hotelOrderTouristMapper.delete(Wrappers.<HotelOrderTourist>lambdaQuery()
                .eq(HotelOrderTourist::getOrderId, id)
                .eq(HotelOrderTourist::getIsDeleted, 0));

        LocalDateTime now = LocalDateTime.now();
        List<HotelOrderTourist> hotelOrderTourists = new ArrayList<>();
        reqs.forEach(req -> {
            HotelOrderTourist hotelOrderTourist = EntityUtil.copy(req, HotelOrderTourist.class);
            hotelOrderTourist.setOrderId(id);
            hotelOrderTourist.setTouristName(StrUtil.concat(true, hotelOrderTourist.getSurname(), hotelOrderTourist.getName()));
            hotelOrderTourist.setCreateId(userId);
            hotelOrderTourist.setGmtCreate(now);
            hotelOrderTourist.setGmtModified(now);
            hotelOrderTourist.setIsDeleted(0);
            hotelOrderTourists.add(hotelOrderTourist);
        });
        hotelOrderTouristMapper.insertBatchSomeColumn(hotelOrderTourists);

        return id;
    }

    /**
     * 构建订单状态
     *
     * @param hotelOrderDetailDTO
     */
    private void buildOrderStatus(HotelOrderDetailDTO hotelOrderDetailDTO) {
        if (OrderPaymentStatus.UN_PAYMENT.getCode().equals(hotelOrderDetailDTO.getPaymentStatus())) {
            if (hotelOrderDetailDTO.getScheduledStatus() == null) {
                // 待付款
                hotelOrderDetailDTO.setOrderStatus(OrderStatus.UN_PAYMENT.getCode());
            }
        } else if (Objects.equals(OrderPaymentStatus.ALREADY_PAYMENT.getCode(), hotelOrderDetailDTO.getPaymentStatus())) {
            if (Objects.equals(hotelOrderDetailDTO.getScheduledStatus(), OrderScheduledStatus.CONFIRM_RESERVE.getCode())) {
                // 待预订
                hotelOrderDetailDTO.setOrderStatus(OrderStatus.CONFIRM_RESERVE.getCode());
            } else if (Objects.equals(OrderScheduledStatus.RESERVE_SUCCESS.getCode(), hotelOrderDetailDTO.getScheduledStatus())) {
                // 确认成功
                hotelOrderDetailDTO.setOrderStatus(OrderStatus.RESERVE_SUCCESS.getCode());
            } else {
                // 确认失败
                hotelOrderDetailDTO.setOrderStatus(OrderStatus.RESERVE_FAIL.getCode());
            }
        } else if (OrderPaymentStatus.ALREADY_CANCEL.getCode().equals(hotelOrderDetailDTO.getPaymentStatus())) {
            // 已取消
            hotelOrderDetailDTO.setOrderStatus(OrderStatus.ALREADY_CANCEL.getCode());
        } else {
            // 确认失败
            hotelOrderDetailDTO.setOrderStatus(OrderStatus.RESERVE_FAIL.getCode());
        }
    }

    /**
     * 发起财务退款
     * @param orderRefunds
     * @param productIds
     * @param productNumber
     * @param productName
     * @param userId
     * @param userFullName
     * @param deptId
     * @param contactName
     * @param contactMobile
     */
    public void finaceRefund(List<HotelOrderRefund> orderRefunds, String orderNumber, List<Long> productIds, String productNumber, String productName, Long userId, String userFullName, Long deptId, String contactName, String contactMobile, Integer touristSource, Long touristSourceId, String touristSourceName) {
        List<BillAddRefundReq> billAddRefundReqs = new ArrayList<>();
        orderRefunds.forEach(hotelOrderRefund -> {
            BillAddRefundReq billAddRefundReq = new BillAddRefundReq();
            billAddRefundReq.setBillNumber(hotelOrderRefund.getRefundNumber());
            billAddRefundReq.setBusinessType(SystemBusinessType.HOTEL.getCode());
            billAddRefundReq.setCollectionAmount(hotelOrderRefund.getRefundAmount());
            billAddRefundReq.setCurrencyId(hotelOrderRefund.getCurrencyId());
            billAddRefundReq.setCurrencyName(hotelOrderRefund.getCurrency());
            billAddRefundReq.setExchangeRate(hotelOrderRefund.getExchangeRate().doubleValue());
            billAddRefundReq.setSaleOrderNumber(orderNumber);
            billAddRefundReq.setSaleOrderId(hotelOrderRefund.getOrderId());
            billAddRefundReq.setProductId(productIds);
            billAddRefundReq.setProductNumber(productNumber);
            billAddRefundReq.setProductName(productName);
            List<String> list = Lists.newArrayList();
            list.add(productName);
            billAddRefundReq.setResourceInfo(list);
            billAddRefundReq.setSaleUserId(userId);
            billAddRefundReq.setSaleUserName(userFullName);
            billAddRefundReq.setSaleDeptId(deptId);
            billAddRefundReq.setRefundTypeId(hotelOrderRefund.getRefundWayId());
            billAddRefundReq.setRefundType(hotelOrderRefund.getRefundWay());
            AccountJson accountJson = new AccountJson();
            accountJson.setCardNumber(hotelOrderRefund.getRefundAccount());
            billAddRefundReq.setRefundAccountJson(accountJson);
            billAddRefundReq.setTouristSource(touristSource);
            billAddRefundReq.setBigClientId(touristSourceId);
            billAddRefundReq.setBigClientName(touristSourceName);
            billAddRefundReq.setTouristName(contactName);
            billAddRefundReq.setContactMobile(contactMobile);
            billAddRefundReq.setRefundTime(hotelOrderRefund.getGmtCreate());
            billAddRefundReq.setPayVoucherJson(Lists.newArrayList());
            billAddRefundReq.setRefundRemark(hotelOrderRefund.getRemark());
            billAddRefundReq.setUserId(userId);
            billAddRefundReqs.add(billAddRefundReq);
        });
        Result result = financeBillService.addRefund(billAddRefundReqs);
        if (!result.isSuccess()) {
            SystemError systemError = SystemError.getDefined(result.getCode());
            throw new BusinessException(systemError);
        }
    }

    /**
     * 根据币种ID获取汇率，获取汇率,
     *
     * @return
     */
    private MainDataCurrencyQueryDTO getExchangeRateByName(Long currencyId) {
        MainDataCurrencyUpdateStatusReq mainDataCurrencyUpdateStatusReq = new MainDataCurrencyUpdateStatusReq();
        mainDataCurrencyUpdateStatusReq.setId(currencyId);
        Result<MainDataCurrencyQueryDTO> queryCurrencyRateResult = mainDataCurrencyService.query(mainDataCurrencyUpdateStatusReq);
        log.info("【查询汇率】exchange rate:{}", JSON.toJSONString(queryCurrencyRateResult));
        if (!queryCurrencyRateResult.isSuccess()) {
            SystemError defined = SystemError.getDefined(queryCurrencyRateResult.getCode());
            throw new BusinessException(defined);
        }
        return queryCurrencyRateResult.getData();
    }
}
